<?php

namespace globalunit\model;

use globalunit\utils\Tools;
use QYS\Db\Mysql;
use QYS\Util\Debug;
use QYS\Log\Log;
use globalunit\utils\DBHelper;
use globalunit\validator\Factory as fc;

function uncamelize($camelCaps,$separator='_')
{
     return strtolower(preg_replace('/([a-z])([A-Z])/', "$1" . $separator . "$2", $camelCaps));
}

Class BaseModel
{
    // 表的名字
    protected $_tblname = null;
    // 数据库
    protected $_db = null;
    //主键
    protected $_pk = 'id';
    //条件
    protected $_where = '';
    //修改内容
    protected $_set = '';
    //分组
    protected $_groupby = '';
    //排序
    protected $_orderby = '';
    //字段
    protected $_field = '*';
    //限制
    protected $_limit = 0;
    //页数
    protected $_page = 1;
    //sql
    protected $_sql = '';
    //是否有效的模型
    protected $_isvalid = true;

    protected $_original = null;

    protected $_validator = null;

    /**对象是否为从数据库中取出来的
     * @param $bool
     * @return bool
     */
    public function isvalid($bool = true)
    {
        return $this->_isvalid = $bool;
    }


    public function __construct($tblname = "")
    {
        $this->init($tblname);
        return $this;
    }

    public function init($tblname = ""){
        if (empty($this->_db)) $this->_db = Mysql::getInstance("mysql1");
        // 当前模型名
        if(!empty($tblname)){
            $this->_tblname = $tblname;
        }
    }
    public function getProperty() {
        $data = [];
        foreach ($this as $k => $v) {
            if(substr($k, 0, 1) != "_" && $k != 'id'){
                $data[] = $k;
            }
        }
        return $data;
    }

    /*where条件
     * @return mixed
     */
    public function where($where = null){
        $this->clearWhere();
        if(!empty($where)){
            if(is_array($where)){
                if(count($where) == count($where, 1)){ //1维数组
                    foreach ($where as $k => $v){
                        if(empty($this->_where)){
                            $this->_where = "$k = $v";
                        }else{
                            $this->_where .= " and $k = $v";
                        }
                    }
                }else if (count($where) == count($where, 2)){ //多维数组
                    foreach ($where as $key => $val){
                        if(is_array($val)){
                            if(!isset($val[0]) || empty($val[0]) || !isset($val[1]) || empty($val[1])){
                                return false;
                            }
                            if(empty($this->_where)){
                                $this->_where = "$key $val[0] $val[1]";
                            }else{
                                $this->_where .= " and $key $val[0] $val[1]";
                            }
                        }else{
                            if(empty($this->_where)){
                                $this->_where = "$key = $val";
                            }else{
                                $this->_where .= " and $key = $val";
                            }
                        }
                    }

                }else{
                    return false;
                }
            }else{
                if(gettype($where) == 'integer' || is_numeric($where)){
                    $this->_where = "$this->_pk = $where";
                }else{
                    $this->_where = $where;
                }
            }
        }
        return $this;
    }

    private function clearWhere(){
        $this->_where = '';
    }
    /*修改字段
     * @return mixed
     */
    private function set($set = null){
        if(!empty($set)){
            if(is_array($set)){
                if(count($set) == count($set, 1)) { //1维数组
                    foreach ($set as $k => $v) {
                        if (empty($this->_set)) {
                            $this->_set = "$k = $v";
                        } else {
                            $this->_set .= ", $k = $v";
                        }
                    }
                }else{
                    return false;
                }
            }else{
                $this->_set = $set;
            }
        }else{
            return false;
        }
        return $this;
    }

    private function clearSet(){
        $this->_set = '';
    }

    public function field($field = '*'){
        $this->_field = $field;
        return $this;
    }

    private function clearField(){
        $this->_field = '*';
    }

    public function group($groupBy){
        $this->_groupby = $groupBy;
        return $this;
    }

    private function clearGroup(){
        $this->_groupby = '';
    }

    public function order($orderBy = null){
        if(!empty($orderBy)){
            if(is_array($orderBy)){
                if(count($orderBy) == count($orderBy, 1)) { //1维数组
                    foreach ($orderBy as $k => $v) {
                        if (empty($this->_orderby)) {
                            $this->_orderby = "$k $v";
                        } else {
                            $this->_orderby .= ", $k $v";
                        }
                    }
                }else{
                    return false;
                }
            }else{
                if (empty($this->_orderby)) {
                    $this->_orderby = $orderBy;
                } else {
                    $this->_orderby .= ", $orderBy";
                }
            }
        }else{
            return false;
        }
        return $this;
    }

    private function clearOrder(){
        $this->_orderby = '';
    }

    public function limit($limit = 0){
        $this->_limit = $limit;
        return $this;
    }

    private function clearLimit(){
        $this->_limit = 0;
    }

    public function page($page = 10){
        $this->_page = $page;
        return $this;
    }

    private function clearPage(){
        $this->_page = 10;
    }


    /**插入对象
     * @return mixed
     * @throws \Exception
     */
    public function insert()
    {
        $obj = $this->itermember();
        $this->init($this->_tblname);
        if (!empty($this->_validator) && $this->_isvalid) {
            foreach ($this->_validator as $col => $value) {
                foreach ($value as $name => $val) {
                    $v = fc::build($name, array('col' => $col, "config" => $val));
                    $obj = $v->validate($obj);
                }
            }
        }

        $this->_sql = DBHelper::insertsql($this->_tblname, $obj);
        Tools::writeLog('sql', $this->_sql);
        $ret= $this->_db->query($this->_sql);
        if($ret){
            if ($this->_validator != null){
                $ac=array();
                foreach ($this->_validator as $col => $value) {
                    foreach ($value as $name => $val) {
                        if($name=='ac'){
                            $ac[$col]=1;
                        }
                    }
                }
                //如果当前数据有自增的主键
                if(array_count_values($ac)>0){
                    $id=$this->_db->insert_id;
                    $keys=array_keys($ac);
                    $key=$keys[0];
                    $this->$key=intval($id);
                }
            }
        }
        return $ret;
    }

    /**获得对象实例
     * @param $where
     * @return bool
     * @throws \Exception
     */
    public function get($where = null)
    {
        if(empty($this->_where) && !empty($where)){
            $this->where($where);
        }
        $this->init($this->_tblname);
        $this->_sql = DBHelper::querysql($this->_tblname, $this->_where);
        Tools::writeLog('sql', $this->_sql);
        $result = $this->_db->query($this->_sql);
        if(!$result){
            return false;
        }
        $data = $result->fetch_assoc();

        if(!empty($data)){
            $member = $this->itermember();
            foreach ($member as $k => $val){
                if(isset($data[$k])){
                    $tp = gettype($this->$k);
                    // Log::var_dump(["k" => $k, "v" => $this->$k, "gettype" => gettype($this->$k)]);
                    switch($tp){
                    case "integer":
                        $this->$k = IntVal($data[$k]);
                        break;
                    default:
                        $this->$k = (String)$data[$k];
                        break;
                    }
                }
            }

            return true;
        }
        return false;
    }

    /**
     * 查询多条记录
     * @param $where
     * @return array
     */
    public function select($where = null)
    {
        if(empty($this->_where) && !empty($where)){
            $this->where($where);
        }
        $this->init($this->_tblname);
        $this->_sql = DBHelper::querysql($this->_tblname, $this->_where, $this->_orderby, $this->_groupby, $this->_limit, $this->_page, $this->_field);
        Tools::writeLog('sql', $this->_sql);
        $result = $this->_db->query($this->_sql);
        $this->clearWhere();
        $this->clearOrder();
        $this->clearGroup();
        $this->clearLimit();
        $this->clearPage();
        $this->clearField();
        $a = [];
        if($result === false){
            return $a;
        }
        $res = $result->fetch_all(MYSQLI_ASSOC);
        $a = [];
        foreach ($res as $k => $v) {
            $c = [];
            foreach ($v as $key => $v1) {
                $tp = gettype($this->$key);
                switch ($tp) {
                    case "integer":
                        $c[$key] = IntVal($v1);
                        break;
                    default:
                        $c[$key] = (string)$v1;
                        break;
                }
            }
            $a[] = $c;
        }
        return  $a;
    }

    /**
     * 原生查询
     * @param $sql
     * @param $type
     * @return array
     */
    public function query($sql, $type = MYSQLI_ASSOC)
    {
        $this->init($this->_tblname);
        $result = $this->_db->query($sql);
        $a = [];
        if($result === false){
            return $a;
        }
        return $result->fetch_all($type);
    }
    /*
     * 查询数量
     *@return int
     * */
    public function count()
    {
        $this->init($this->_tblname);
        $this->_sql = DBHelper::querysql($this->_tblname, $this->_where, $this->_orderby, $this->_groupby, $this->_limit, $this->_page, "COUNT(`id`) as count");
        Tools::writeLog('sql', $this->_sql);
        $result = $this->_db->query($this->_sql);
        $this->clearWhere();
        $this->clearField();
        if($result === false){
            return 0;
        }
        $result = $result->fetch_assoc();
        return (int)$result['count'];
    }


    public function initWithData($data, $op = 'select')
    {
        $member = $this->itermember();

        if(!empty($data)){
            foreach ($member as $k => $val){
                if(isset($data[$k])){
                    $tp = gettype($this->$k);
                    switch($tp){
                    case "integer":
                        $this->$k = isset($data[$k]) ? IntVal($data[$k]) : 0;
                        break;
                    default:
                        $this->$k = (String)$data[$k];
                        break;
                    }
                }
            }
            return true;
        }
        return false;
    }

    public function getChildModel() {
        return new static();
    }

    /**同步对象到数据库
     * @return mixed
     */
    public function save()
    {
        $this->init($this->_tblname);
        $member = $this->itermember();
        $where = gettype($this->id) == "string" ? "id = '$this->id'" : "id = ".$this->id;
        $this->_sql = DBHelper::udpatesql($this->_tblname, $member, $where);
        Tools::writeLog('sql', $this->_sql);
        $this->_db->query($this->_sql);
        return $this->_db->affected_rows;
    }

    public function upsert($where)
    {
        $this->init($this->_tblname);
        if(empty($this->_where) && !empty($where)){
            $this->where($where);
        }
        $obj = $this->itermember();
        $this->_sql = DBHelper::upsertsql($this->_tblname, $obj, $this->_where);
        Tools::writeLog('sql', $this->_sql);
        $ret = $this->_db->query($this->_sql);
        return $ret;
    }
    /*批量修改
     * @return mixed
     */
    public function saveAll($set = null, $where = null)
    {
        if(empty($this->_set)){
            $this->set($set);
        }
        if(empty($this->_where) && !empty($where)){
            $this->where($where);
        }
        $this->init($this->_tblname);
        $this->_sql = DBHelper::udpatesql($this->_tblname, $this->_set, $this->_where);
        Tools::writeLog('sql', $this->_sql);
        $this->_db->query($this->_sql);
        $this->clearWhere();
        $this->clearSet();
        return $this->_db->affected_rows;
    }

    /**删除对象
     * @param $where
     * @return mixed
     */
    public function delete($where = null)
    {
        if(empty($this->_where) && !empty($where)){
            $this->where($where);
        }
        $this->init($this->_tblname);
        $this->_sql = "DELETE FROM `$this->_tblname` WHERE $this->_where";
        Tools::writeLog('sql', $this->_sql);
        $this->clearWhere();
        return $this->_db->query($this->_sql);
    }
    /**对象列表
     * @return array
     */
    public function listObject($arraylist){
        $a = [];
        $s = new static($this->_tblname);
        foreach ($arraylist as $k => $v){
            $s->initWithData($v);
            $a[] = $s;
        }
        return $a;
    }

    /**对象列表转数组列表
     * @return array
     */
    public function listArray($objectlist){
        $a = [];
        foreach ($objectlist as $k => $v){
            $a[] = $v->toarray();
        }
        return $a;
    }

    public static function asArrayList($objectlist){
        $a = [];
        foreach ($objectlist as $k => $v){
            $a[] = $v->toarray();
        }
        return $a;
    }

    /**模型对象转换成哈希表
     * @return array
     */
    public function toarray()
    {
        $a = $this->itermember();
        return $a;
    }

    public function getLastSql(){
        return $this->_sql;
    }

    protected function itermember()
    {
        $a = array();
        foreach ($this as $key => $value) {
            if (substr($key, 0, 1) != "_") {
                if(gettype($value)=='integer'){
                    $a[$key] = IntVal($value);
                }elseif (gettype($value)=='double'){
                    $a[$key] = (float)$value;
                }elseif (gettype($value)=='float'){
                    $a[$key] = (float)$value;
                }elseif (gettype($value)=='string'){
                    $a[$key] = (String)$value;
                }elseif (gettype($value)=='NULL'){
                }elseif (gettype($value)==''){
                    $a[$key] = (String)$value;
                }else{
                    $clazzname = get_class($value);
                    if($clazzname=='DateTime'){
                        $a[$key]= (String)$value->format('Y-m-d H:i:s');
                    }else{
                        $a[$key] = $value;
                    }
                }
            }
        }
        return $a;
    }

    public function __call($method, $args)
    {
        return call_user_func_array([$this, $method], $args);
    }

    public static function __callStatic($method, $args)
    {
        $model = new static();
        return call_user_func_array([$model, $method], $args);
    }

}
